/**
 * vim: filetype=c:fenc=utf-8:ts=4:et:sw=4:sts=4
 */
#include <stddef.h>
#include "kernel.h"
#define SEM_COUNT_MAX 20

//实验4：信号量


//实验4：信号量
typedef struct{
    int _val;
    int _id;
    struct wait_queue *_wq;
}SEM;

//const int SEM_COUNT_MAX = 20;//信号量最大数量
SEM* semidhash[SEM_COUNT_MAX];//信号量id哈希表
int stsem[SEM_COUNT_MAX]={0};//看对应下标是否储存信号量指针
struct wait_queue * sem_wq[SEM_COUNT_MAX];//信号量等待队列


int sys_sem_create(int value)
{
    uint32_t flags;
    SEM *sem = (SEM *)kmalloc(sizeof(SEM));
    if (sem == NULL) {
        return -1; // Failed to allocate memory for semaphore
    }
    save_flags_cli(flags);
    int begin = 1;
    while(stsem[begin])
    {
        begin++;
        if(begin >= SEM_COUNT_MAX)
            return -1;
    }
    sem->_id = begin;
    sem->_val = value;
    sem->_wq = NULL;
    //修改st数组
    stsem[begin] = 1;
    semidhash[begin] = sem;
    restore_flags(flags);

    printk("create sem %d\n",begin);
    return begin;
}

int sys_sem_destroy(int semid)
{
    if (semid < 1 || semid >= SEM_COUNT_MAX || stsem[semid] == 0) {
        return -1; // Invalid semaphore ID
    }
    
    SEM * sem = semidhash[semid];
    if (sem == NULL) {
        return -1; // Semaphore not found
    }
    // Free the semaphore memory
    kfree(sem);
    // Remove the semaphore from the hash table
    semidhash[semid] = NULL;
    // Mark the semaphore as destroyed
    stsem[semid] = 0;
    return 0;
}

int sys_sem_wait(int semid)
{
    if (semid < 1 || semid >= SEM_COUNT_MAX || stsem[semid] == 0) {
        return -1; // Invalid semaphore ID
    }
    SEM* sem = semidhash[semid];
    uint32_t flags;
    save_flags_cli(flags);
    sem->_val--;
    // printk("sem %d wait %d\n",semid,sem->_val);
    if (sem->_val < 0) {
        sleep_on(&(sem->_wq));
    }
    restore_flags(flags);


    return 0;
}

int sys_sem_signal(int semid)
{
    if (semid < 1 || semid >= SEM_COUNT_MAX || stsem[semid] == 0) {
        return -1; // Invalid semaphore ID
    }

    
    SEM* sem = semidhash[semid];

    uint32_t flags;
    save_flags_cli(flags);
    sem->_val++;
    // printk("sem %d signal %d\n",semid,sem->_val);
    if (sem->_val <= 0) {
        wake_up(&(sem->_wq),1);
    }
    restore_flags(flags);

    return 0;
}

//

